import time, os, sqlite3
from threading import Thread
import numpy as np
import pandas as pd
from tqsdk import TqApi, TqAuth, TqKq
from rich.console import Console
from rich.theme import Theme
from MyTT import REF, EMA, SUM
import logging

# 配置日志记录
logging.basicConfig(
    filename='trading_log.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# 改变控制台背景色和字体色，控制台窗口大小
os.system("COLOR 02")
os.system("mode con cols=150 lines=50")

# 定义颜色主题
# 定义更明亮显眼的颜色主题
custom_theme = Theme({
    "info": "bright_cyan",
    "warning": "bright_yellow",
    "error": "bright_red",
    "success": "bright_green",
    "trade": "bold bright_magenta"
})
console = Console(theme=custom_theme)

# 定义全局变量
symbols = []
api = None
threads = []


def get_symbols():
    try:
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM products WHERE is_monitored=1")
        products = cursor.fetchall()
        conn.close()
        symbols = [row[2] for row in products]
    except Exception as e:
        print(f"从数据库获取监控品种时出错: {e}", style="error")
    return symbols


def stop_loss(symbol, minites):
    try:
        conn = sqlite3.connect('trade_monitor.db')
        cursor = conn.cursor()
        cursor.execute("SELECT limit_stoploss FROM products WHERE exchange_code=? AND is_monitored=1", (symbol,))
        result = cursor.fetchone()
        conn.close()
        if result is None:
            stop_loss_limit = 3000
        else:
            stop_loss_limit = result[0]            
    except Exception as e:
        console.print(f"从数据库获取 {symbol} 止损限额时出错: {e}", style="error")
        return
    console.print(f"{time.strftime('%X')} 开始检查{symbol}止损条件", style="warning")
    klines = api.get_kline_serial(symbol, 60 * minites, data_length=300)
    quote = api.get_quote(symbol)
    position = api.get_position(symbol)
    orders = api.get_order(symbol)

    console.print(f"{time.strftime('%X')} 开始处理 {symbol}", style="warning")
    if True:
        console.print(f"{time.strftime('%X')} 数据更新", style="info")
        try:
            # 撤销所有未成交订单
            for order in orders.items():
                if hasattr(order, 'status') and order.status == 'ALIVE':
                    api.cancel_order(order)

            # ***************************************限额止损检查***************************************
            if position.pos_short > 0:
                short_loss_per_hand = (position.open_price_short - quote.last_price) * quote.volume_multiple 
                if short_loss_per_hand > stop_loss_limit:
                    if symbol.startswith('SHFE'):
                        if position.pos_short_today > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="CLOSETODAY",
                                volume=position.pos_short_today,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今空仓(限额止损): 手数: {position.pos_short_today}",
                                style="trade"
                            )
                            # 仅保留下单信息日志
                            logging.info(
                                f"平SHFE{symbol}今空仓(限额止损): 手数: {position.pos_short_today}, 平仓价格: {limit_price}"
                            )
                        if position.pos_short_his > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="CLOSE",
                                volume=position.pos_short_his,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨空仓(限额止损): 手数: {position.pos_short_his}",
                                style="trade"
                            )
                            # 仅保留下单信息日志
                            logging.info(
                                f"平SHFE{symbol}昨空仓(限额止损): 手数: {position.pos_short_his}, 平仓价格: {limit_price}"
                            )
                    else:
                        limit_price = quote.ask_price1 + 2 * quote.price_tick
                        api.insert_order(
                            symbol=symbol,
                            direction="CLOSE",
                            volume=position.pos_short,
                            limit_price=limit_price
                        )
                        console.print(
                            f"{time.strftime('%X')} 平{symbol}空仓(限额止损): 手数: {position.pos_short}",
                            style="trade"
                        )
                        # 仅保留下单信息日志
                        logging.info(
                            f"平{symbol}空仓(限额止损): 手数: {position.pos_short}, 平仓价格: {limit_price}"
                        )

            if position.pos_long > 0:
                long_loss_per_hand = (quote.last_price - position.open_price_long) * quote.volume_multiple 
                if long_loss_per_hand > stop_loss_limit:
                    if symbol.startswith('SHFE'):
                        if position.pos_long_today > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="CLOSETODAY",
                                volume=position.pos_long_today,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今多仓(限额止损): 手数: {position.pos_long_today}",
                                style="trade"
                            )
                            # 仅保留下单信息日志
                            logging.info(
                                f"平SHFE{symbol}今多仓(限额止损): 手数: {position.pos_long_today}, 平仓价格: {limit_price}"
                            )
                        if position.pos_long_his > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="CLOSE",
                                volume=position.pos_long_his,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨多仓(限额止损): 手数: {position.pos_long_his}",
                                style="trade"
                            )
                            # 仅保留下单信息日志
                            logging.info(
                                f"平SHFE{symbol}昨多仓(限额止损): 手数: {position.pos_long_his}, 平仓价格: {limit_price}"
                            )
                    else:
                        limit_price = quote.bid_price1 - 2 * quote.price_tick
                        api.insert_order(
                            symbol=symbol,
                            direction="SELL",
                            offset="CLOSE",
                            volume=position.pos_long,
                            limit_price=limit_price
                        )
                        console.print(
                            f"{time.strftime('%X')} 平{symbol}多仓(限额止损): 手数: {position.pos_long}",
                            style="trade"
                        )
                        # 仅保留下单信息日志
                        logging.info(
                            f"平{symbol}多仓(限额止损): 手数: {position.pos_long}, 平仓价格: {limit_price}"
                        )

            # ***************************************趋势追踪止损检查***************************************
            close = klines.close
            low = klines.low
            open = klines.open
            high = klines.high
            close = np.array(close)
            low = np.array(low)
            open = np.array(open)
            high = np.array(high)

            Q = (3 * close + low + open + high) / 6
            terms = [
                26 * Q,
                25 * REF(Q, 1),
                24 * REF(Q, 2),
                23 * REF(Q, 3),
                22 * REF(Q, 4),
                21 * REF(Q, 5),
                20 * REF(Q, 6),
                19 * REF(Q, 7),
                18 * REF(Q, 8),
                17 * REF(Q, 9),
                16 * REF(Q, 10),
                15 * REF(Q, 11),
                14 * REF(Q, 12),
                13 * REF(Q, 13),
                12 * REF(Q, 14),
                11 * REF(Q, 15),
                10 * REF(Q, 16),
                9 * REF(Q, 17),
                8 * REF(Q, 18),
                7 * REF(Q, 19),
                6 * REF(Q, 20),
                5 * REF(Q, 21),
                4 * REF(Q, 22),
                3 * REF(Q, 23),
                2 * REF(Q, 24),
                REF(Q, 25)
            ]
            trading_line = sum(terms) / 351
            short_line = EMA(trading_line, 7)
           #logging.info(f"Symbol: {symbol}, Trading Line[-2]: {trading_line[-2]}, Short Line[-2]: {short_line[-2]}")
            console.print(f"条件值是： {trading_line[-2]}, {short_line[-2]}",style="trade")

            if len(trading_line) >= 2 and len(short_line) >= 2:
                # 处理空单
                if position.pos_short > 0 and trading_line[-2] > short_line[-2]:
                    if symbol.startswith('SHFE'):
                        if position.pos_short_today > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="CLOSETODAY",
                                volume=position.pos_short_today,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今空仓(均线追踪止损): 手数: {position.pos_short_today}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}今空仓(均线追踪止损): 手数: {position.pos_short_today}, 平仓价格: {limit_price}"
                            )
                        if position.pos_short_his > 0:
                            limit_price = quote.ask_price1 + 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="BUY",
                                offset="CLOSE",
                                volume=position.pos_short_his,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨空仓(均线追踪止损): 手数: {position.pos_short_his}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}昨空仓(均线追踪止损): 手数: {position.pos_short_his}, 平仓价格: {limit_price}"
                            )
                    else:
                        limit_price = quote.ask_price1 + 2 * quote.price_tick
                        api.insert_order(
                            symbol=symbol,
                            direction="BUY",
                            offset="CLOSE",
                            volume=position.pos_short,
                            limit_price=limit_price
                        )
                        console.print(
                            f"{time.strftime('%X')} 平{symbol}空仓(均线追踪止损): 手数: {position.pos_short}",
                            style="trade"
                        )
                        logging.info(
                            f"平{symbol}空仓(均线追踪止损): 手数: {position.pos_short}, 平仓价格: {limit_price}"
                        )
                # 处理多单
                if position.pos_long > 0 and trading_line[-2] < short_line[-2]:
                    if symbol.startswith('SHFE'):
                        if position.pos_long_today > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="CLOSETODAY",
                                volume=position.pos_long_today,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}今多仓(均线追踪止损): 手数: {position.pos_long_today}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}今多仓(均线追踪止损): 手数: {position.pos_long_today}, 平仓价格: {limit_price}"
                            )
                        if position.pos_long_his > 0:
                            limit_price = quote.bid_price1 - 2 * quote.price_tick
                            api.insert_order(
                                symbol=symbol,
                                direction="SELL",
                                offset="CLOSE",
                                volume=position.pos_long_his,
                                limit_price=limit_price
                            )
                            console.print(
                                f"{time.strftime('%X')} 平SHFE{symbol}昨多仓(均线追踪止损): 手数: {position.pos_long_his}",
                                style="trade"
                            )
                            logging.info(
                                f"平SHFE{symbol}昨多仓(均线追踪止损): 手数: {position.pos_long_his}, 平仓价格: {limit_price}"
                            )
                    else:
                        limit_price = quote.bid_price1 - 2 * quote.price_tick
                        api.insert_order(
                            symbol=symbol,
                            direction="SELL",
                            offset="CLOSE",
                            volume=position.pos_long,
                            limit_price=limit_price
                        )
                        console.print(
                            f"{time.strftime('%X')} 平{symbol}多仓(均线追踪止损): 手数: {position.pos_long}",
                            style="trade"
                        )
                        logging.info(
                            f"平{symbol}多仓(均线追踪止损): 手数: {position.pos_long}, 平仓价格: {limit_price}"
                        )

        except Exception as e:
            console.print(f"处理 {symbol} 止损逻辑时出错: {e}", style="error")
            # 移除错误日志记录


if __name__ == "__main__":
    try:
        api = TqApi(account=TqKq(), auth=TqAuth("cps168", "alibaba"))
        symbols = get_symbols()
        minites = 5
        while True:
            deadline = time.time() + 2
            api.wait_update(deadline=deadline)
            console.print(f"**********{time.strftime('%X')} **********", style="warning")
            for symbol in symbols:
                stop_loss(symbol, minites)

    except KeyboardInterrupt:
        pass
    finally:
        api.close()
        console.print("程序已停止", style="info")